import socketServices from "@/services/socket/index.js"
import $store from '@/store/index.js';
import msgSqlite from "@/sqlite_services/msg.js"
class WebSocketClient {
	constructor(urls, options = {}) {
		if (WebSocketClient.instance) {
			return WebSocketClient.instance;
		}

		this.urls = urls;
		this.currentUrlIndex = 0; // 当前使用的 URL 索引
		this.options = {
			...WebSocketClient.defaultOptions,
			...options,
		};
		this.firstConnection = true //第一次连接成功
		this.socketTask = null;
		this.isConnected = false;
		this.reconnectCount = 0;
		this.timer = null;
		this.responseTimer = null; //回应计时器
		this.messageHandler = null;
		this.isReconnecting = false; // 新增：重连状态标志
		this.activeShutdown = false //主动关闭标识
		// 监听网络状态变化
		uni.onNetworkStatusChange(this.reconnectIfConnected.bind(this));

		WebSocketClient.instance = this;
	}

	/**
	 * 获取默认配置选项
	 * 该静态方法提供了一组默认的配置选项，可用于初始化过程或作为配置的默认基线。
	 * 这些选项包括关于网络连接、消息处理和回调函数的各种设置。
	 * 
	 * @return {Object} 返回一个包含默认配置选项的对象。
	 */
	static get defaultOptions() {
		return {
			header: {}, // 请求头的默认配置，为空对象
			protocols: [], // 支持的协议列表，默认为空数组
			tcpNoDelay: true, // 是否启用TCP的延迟发送，true为禁用延迟发送
			perMessageDeflate: false, // 是否启用消息压缩，默认为false
			timeout: 60000, // 连接超时时间，默认为60000毫秒
			sslVerify: true, // 是否进行SSL验证，默认为true
			sslVerifyHost: false, // 是否验证主机名，默认为false，即不验证
			success: () => {}, // 连接成功时的回调函数，默认为空函数
			fail: () => {}, // 连接失败时的回调函数，默认为空函数
			heartbeatInterval: 2500, // 心跳间隔时间，默认为5000毫秒
			maxReconnectAttempts: 5, // 最大重连尝试次数，默认为3次
			missedPings: 0, // 初始化未收到回应的心跳次数  15次主动断连
			reconnectTimeout: 5000, // 重连尝试的超时时间，默认为5000毫秒
			messageDispatcher: null, // 消息分发器，默认为null，用于自定义消息处理
		};
	}
	

	async connect(newConnection = false) {
		//如果是新连接，就是重新登录的
		if(newConnection){
			this.maxReconnectAttempts = 5
			this.missedPings = 0
			this.isReconnecting = false
			this.isConnected = false
		}
		if (this.isConnected || this.isReconnecting) return; // 如果正在重连，返回
		this.isReconnecting = true;
		try {
			await this._connect();
		} catch (err) {
			console.error('连接失败', err); // 显示具体错误
			this.options.fail(err);
		} finally {
			this.isReconnecting = false; // 无论连接成功或失败，重置重连状态
		}
	}




	async _connect() {
		this.socketTask = null
		this.activeShutdown = false
		try {
			console.log('当前socketUrl:',this.urls[this.currentUrlIndex]);
			this.socketTask = uni.connectSocket({
				url: this.urls[this.currentUrlIndex], // 使用当前的 URL,
				...this.options,
				header: {
					'AUTHORIZATION': 'Bearer ' + uni.getStorageSync('token')
				},
				success: () => {
					console.log('WebSocket接口调用成功');
					this.bindSocketEvents();
					this.options.success();
				},
				fail: (err) => {
					console.error('WebSocket接口调用失败', err);
					this.reconnect();
					this.options.fail(err);
				},
			});
			this.socketTask.binaryType = "arraybuffer"
			// 等待连接完成或超时
			const timeoutPromise = new Promise((_, reject) => setTimeout(reject, this.options.timeout));
			const openPromise = uni.onSocketOpen(() => Promise.resolve());
			await Promise.race([timeoutPromise, openPromise]);
		} catch (err) {
			throw err;
		}
	}
	//主动关闭
	close() {
		this.activeShutdown = true
		this.isConnected = false;
		this.firstConnection = true
		this.clearTimers()
		if (this.socketTask) {
			this.socketTask.close({
				code:500,
				success: function(res) {
					console.log("WebSocket关闭成功！");  
				},  
				fail: function(res) {  
					console.log("WebSocket关闭失败！");  
				} 
			})
		}
		console.log('WebSocket已手动关闭');
	}
	//程序关闭，比如心跳超时
	routineClose() {
		this.activeShutdown = false
		this.isConnected = false;
		this.clearTimers()
		if (this.socketTask) {
			this.socketTask.close({
				code:500,
				success: function(res) {
					console.log("WebSocket关闭成功！");  
				},  
				fail: function(res) {  
					console.log("WebSocket关闭失败！");  
				} 
			})
		}

		console.log('WebSocket已由程序关闭');
	}
	clearTimers() {
		if (this.timer) clearInterval(this.timer);
		if (this.responseTimer) clearTimeout(this.responseTimer);
		this.timer = null;
		this.responseTimer = null;
	}
	//手动重连
	async activeReconnect() {
		this.currentUrlIndex = 0,//从第一个索引重连
		this.reconnectCount = 0
		$store.commit('$uStore', {
			name: 'reconnectCount',
			value: this.reconnectCount
		})
		await this.connect()
	}
	reconnect() {
		//如果正在重连，或者主动断开
		if (this.isReconnecting || this.activeShutdown) return;
		this.attemptReconnect();
	}

	async attemptReconnect() {
		if (this.reconnectCount >= this.options.maxReconnectAttempts) {
			console.warn('达到最大重连次数');
			// 尝试更换 URL
			this.currentUrlIndex = (this.currentUrlIndex + 1) % this.urls.length;
			// 如果所有 URL 都尝试过仍然失败，则不再重连
			if (this.currentUrlIndex === 0) {
				console.error('所有 WebSocket URL 尝试失败');
				return;
			}
			console.log(`更换 WebSocket URL: ${this.urls[this.currentUrlIndex]}`);
			// 切换了新的连接重置重连次数
			this.reconnectCount = 0;
		}

		try {
			// await this.close();
			await new Promise((resolve) => setTimeout(resolve, this.options.reconnectTimeout));
			await this.connect();
		} catch (err) {
			console.error('重连失败', err); 
		}
		this.reconnectCount++;
		$store.commit('$uStore', {
			name: 'reconnectCount',
			value: this.reconnectCount
		})
	}

	initHeartbeat() {
		this.clearTimers(); // 防止重复初始化心跳定时器
		this.missedPings = 0; // 初始化未收到回应的心跳次数
		this.timer = setInterval(() => {
			if (this.isConnected) {
				this.sendPing();
				// 设置一个计时器，在一定时间内未收到任何回应则进行重连
				this.responseTimer = setTimeout(() => {
					this.missedPings++;
					console.warn(`第 ${this.missedPings} 次未收到回应`);

					if (this.missedPings >= 15) {
						console.error('连续 15 次未收到回应，尝试重连');
						//断开并重连
						this.missedPings = 0;
						this.routineClose()
					}
				}, this.options.heartbeatInterval);
			} else {
				clearInterval(this.timer); // 停止心跳包的发送
			}
		}, this.options.heartbeatInterval);
		// 监听任何回应
		this.setMessageHandler((res) => {
			clearTimeout(this.responseTimer); // 清除计时器
			this.missedPings = 0; // 重置计数器
		});
	}


	sendPing() {
		this.send({
			action: "heart"
		});
	}

	bindSocketEvents() {
		uni.onSocketOpen((e) => {
			console.log('WebSocket连接已打开');
			//不是第一次连接
			if(!this.firstConnection){
				$store.dispatch('anewGetFriend')
			}
			//清空本次链接缓存的群列表
			$store.commit('clearOpenGroups')
			
			//清空本次链接缓存的私聊列表
			$store.commit('clearOpenPrivates')
			
			//链接打开如果在群页面更新下配置
			uni.$emit('chatOperation', {
				type: 'grouprefresh'
			})
			
			this.isConnected = true;
			this.activeShutdown = false; // 重置主动关闭标志
			if(this.firstConnection)this.firstConnection = false

			// 注释主动拉取离线消息，由后台推送
			// //延迟500毫秒拉离线，目的避免服务器推送的消息现在接不到
			// setTimeout(()=>{
			// 	//拉取离线
			// 	msgSqlite.getMessageOffline()
			// },500)


			$store.commit('$uStore', {
				name: 'isConnected',
				value: true
			})

			this.initHeartbeat();
			this.reconnectCount = 0; // 添加重置重连次数

			$store.commit('$uStore', {
				name: 'reconnectCount',
				value: 0
			})
		});

		uni.onSocketClose((e) => {
			console.error('WebSocket连接关闭', e);
			this.clearTimers(); // 添加清除计时器
			this.isConnected = false;

			$store.commit('$uStore', {
				name: 'isConnected',
				value: false
			})
			// 如果是主动关闭，则不重连
			if (this.activeShutdown) {
				return;
			}

			// 否则尝试重连
			this.reconnect();
		});

		uni.onSocketError((err) => {
			console.error('WebSocket连接出错', err);
			this.clearTimers(); // 添加清除计时器
			this.isConnected = false;

			$store.commit('$uStore', {
				name: 'isConnected',
				value: false
			})
			// 如果是主动关闭，则不重连
			if (this.activeShutdown) {
				return;
			}
			this.reconnect();
		});

		uni.onSocketMessage((res) => {
			socketServices.receive(res)
			if (this.messageHandler) {
				this.messageHandler(res);
			}
			if (this.options.messageDispatcher) {
				this.options.messageDispatcher(res.data);
			}
		});
	}

	send(data) {
		return new Promise((resolve, reject) => {
			if (this.isConnected) {
				uni.sendSocketMessage({
					data: typeof data === 'string' ? data : JSON.stringify(data),
					success: () => {
						// console.log('发送消息成功');
						resolve();
					},
					fail: (err) => {
						console.error('发送消息失败', err);
						reject(err);
					},
				});
			} else {
				console.error('WebSocket未连接，无法发送消息');
				reject(new Error('WebSocket未连接'));
			}
		});
	}

	setMessageHandler(handler) {
		this.messageHandler = handler;
	}

	reconnectIfConnected(res) {
		if (!res.isConnected && this.isConnected) {
			//          uni.showToast({
			// 	title: '网络已断开，正在重连...',
			// 	icon: 'none',
			// 	duration: 2000
			// });
			this.reconnect();
		}
	}
	

	static getInstance(urls, options) {
		if (!WebSocketClient.instance) {
			WebSocketClient.instance = new WebSocketClient(urls, options);
		}
		return WebSocketClient.instance;
	}
}

export default WebSocketClient;